/**
 * The Woosta True Fidelity Engine
 *
 * License... etc.
 **
 * Neural Networks
 *
 * An implementation of neural networks with back
 * propagation, parallelized using futures.
 **
 * Author: Sean Micklethwaite
 **/

#ifndef __neural_netH__
#define __neural_netH__

#include "thread.h"
#include "wtftypes.h"
#include <vector>

namespace Rtl
{
	class BaseNeuron : public WtfEngine::WorkItem
	{
	public:
		typedef tScalar (*tSigmoidFunc)(tScalar, tScalar);

		/**
		 * A connection between neurons
		 **/
		struct Synapse
		{
			tScalar		Weight;
			BaseNeuron*	pInput;

			Synapse(tScalar w, BaseNeuron* p)
				: Weight(w), pInput(p) {};
		};

	protected:
		tScalar			mThreshold;
		tScalar			mValue;
		tSigmoidFunc	mpSigmoid;
		unsigned		mId;

	public:
		BaseNeuron(tScalar thresh, tSigmoidFunc s, unsigned id)
			: WtfEngine::WorkItem(), mThreshold(thresh), mpSigmoid(s), mId(id){

		};

		void Feedback(tScalar score, tScalar influence);

		inline tScalar GetValue(){
			Sync();
			return mValue;
		};

		inline unsigned GetId(){
			return mId;
		};
	};

	class Neuron : public BaseNeuron
	{
	private:
		std::vector<Synapse>	mInputs;

	public:
		Neuron(tScalar thresh, tSigmoidFunc s, unsigned id)
			: BaseNeuron(thresh, s, id) {

		};

		// Evaluates the value
		void operator ()(void);

		void AddInput(BaseNeuron* pInput, tScalar w){
			mInputs.push_back(Synapse(w, pInput));
		};
	};

	class InputNeuron : public BaseNeuron
	{
	private:
		tScalar	mInput;

	public:
		InputNeuron(tScalar thresh, tSigmoidFunc s, unsigned id)
			: BaseNeuron(thresh, s, id) {

		};

		void Create(tScalar input){
			mInput = input;
			this->BaseNeuron::Create();
		};

		// Evaluates the value
		void operator ()(void);
	};

	class NeuralNet : public WtfEngine::GcObject
	{
	private:
		tScalar	mPropagationRate;

		std::vector<InputNeuron*>	mzpInputLayer;
		std::vector<Neuron*>		mzpHiddenLayer;
		std::vector<Neuron*>		mzpOutputLayer;

	public:
		void Evaluate(const tScalar* zInput, tScalar* zOutput);

		/**
		 * Delivers feedback on the previous result computed by the
		 * network. A negative score indicates a poor result, a positive
		 * score indicates a good result.
		 **/
		void Feedback(tScalar score);

		void Feedback(tScalar score, unsigned id);

		void Load(tConstString sFile);
		void Save(tConstString sFile);

		static tScalar _ThresholdFunc(tScalar t, tScalar v);

		typedef WtfEngine::GcReference<NeuralNet>	tRef;
	};
};

#endif
